import java.util.ArrayList;
import java.util.Collections;
/**
 * class VectorPosHandling 
 * 
 * Includes a list of functions, to find the lengths of connected coins, and
 * places for missing coins as well.
 * @author jenc, jeppe
 *
 */
public class VectorPosHandling 
{	
	public ArrayList<VectorPos> list = new ArrayList<VectorPos>();
	private int numOfPostitions = 0;
	private VectorPos firstYPos;
	private VectorPos firstXPos;
	private VectorPos firstXYPos = new VectorPos(Common.NOVALUE, Common.NOVALUE);
	/**
	 * Create a new Arraylist of VectorPos and returns a pointer 
	 * @return
	 */
	public VectorPosHandling copyVH()
	{
		VectorPosHandling vhnew = new VectorPosHandling();		
		vhnew.list = new ArrayList<VectorPos>(this.list);
		return vhnew;
	}
	/**
	 * Adds a new vector, based on the class VectorPos
	 * @param p
	 */
	public void addVectorPos(VectorPos p)
	{	
		if(!list.contains(p))
		{
			list.add(p);
			Collections.sort(list, new VectorComparatorX());	
			numOfPostitions++;			
		}
	}
	/**
	 * Sorts the collections, regards to X
	 */
	public void sortX()
	{	
		Collections.sort(list, new VectorComparatorX());			
	}
	/**
	 * Sorts the collections, regards to Y
	 */
	public void sortY()
	{
		Collections.sort(list, new VectorComparatorY());		
	}	
	/**
	 * Checks if a VectorPos belongs to a list
	 * @param check
	 * @return
	 */
	public boolean checkPosition(VectorPos check)
	{
		return list.contains((VectorPos)check);
	}
	/**
	 * showList()
	 * 
	 * Displays the list of positions of the state
	 */
	public void showList()
	{
		for(int i=0;i<numOfPostitions;i++)
		{
			VectorPos p = (VectorPos)list.get(i);
			System.out.println(p.xPos+" "+p.yPos);			
		}
	}
	/**
	 * Finds the longest horizontal connected list of coins
	 *
	 * @return 
	 */
	public int getLongestX()
	{
		// sort the list according to x
		sortY();
		int xlength = 1;
		int oldxlength = 0;
		boolean firstCheck = true;
		for(int i=1;i<list.size();i++)
		{
			VectorPos p1 = list.get(i-1);
			VectorPos p2 = list.get(i);
			if((p1.yPos == p2.yPos) && (p2.xPos - p1.xPos)==1)
			{
				if(firstCheck)
				{
					firstXPos = p1;
					firstCheck = false;
				}
				xlength++;
			}
			else
			{
				if(oldxlength<xlength)
				{
					firstCheck = true;
					oldxlength = xlength;	
				}
				xlength = 1;					
			}
		}
		// if we get a new xlength that has not been saved
		// we check the last time.
		if(xlength<oldxlength)
			xlength = oldxlength;
	
		return xlength;
	}
	/**
	 * Find the longest Vertical list of connected coins.
	 * @return
	 */
	public int getLongestY()
	{
		sortX();
		boolean firstCheck = true;
		int ylength = 1;
		int oldylength = 1;		
		for(int i=1;i<list.size();i++)
		{
			VectorPos p1 = list.get(i-1);
			VectorPos p2 = list.get(i);

			if((p1.xPos == p2.xPos)&&(p1.yPos+1==p2.yPos))
			{						
				ylength++;
				if(firstCheck) 
				{ 
					firstYPos  = p1; 
					firstCheck = false;
				}
			}
			else
			{
				if(oldylength<ylength)
				{
					firstCheck = true;
					oldylength = ylength;
				}
				ylength = 1;
			}
		}
		// if we get a new ylength that has not been saved
		// we check the last time.
		if(ylength<oldylength)
			ylength = oldylength;
		// return the final length (most longest)
		return ylength;
	}
	/**
	 * Finds the longest diagonal, desc or asc. and return the largest number of those 2
	 * @return
	 */
	public int getLongestXY()
	{
		sortX();
		boolean direction = true;
		VectorPos temp = null;
		VectorPos UP = null;
		VectorPos DOWN = null;		
		int oldxylength = 1;		
		for(int ii=0;ii<list.size();ii++)
		{
			VectorPos p1 = list.get(ii);
			int xylengthUP = 1;
			int xylengthDOWN = 1;	
			int testXup = p1.xPos;
			int testYup = p1.yPos;
			int testXdown = p1.xPos;
			int testYdown = p1.yPos;

			for(int i=1+ii;i<list.size();i++)
			{
				VectorPos p2 = list.get(i);
				// test of the list is ascending
				if((testXup+1)==(p2.xPos) && (testYup+1)==(p2.yPos))
				{  
					testXup = p2.xPos;
					testYup = p2.yPos;
					UP = p2;
					xylengthUP++;
				} 
				// test of the list is descending
				if((testXdown+2)==(p2.xPos+1) && (testYdown)==(p2.yPos+1))
				{
					testXdown = p2.xPos;
					testYdown = p2.yPos;
					DOWN = p2;
					xylengthDOWN++;
				}
			}
			if(xylengthDOWN>xylengthUP)
			{
				if(oldxylength<xylengthDOWN)
				{
					temp = DOWN;
					direction = false;
					oldxylength = xylengthDOWN;	
				}
			} 
			else
			{
				if(oldxylength<xylengthUP)
				{
					temp = UP;
					direction = true;
					oldxylength = xylengthUP;
				}				
			}
		}
		/*
		 * If there is a position, save it for later
		 * use
		 */
		if(temp!=null)
			if(direction)
			{
				firstXYPos.xPos = temp.xPos+1;
				firstXYPos.yPos = temp.yPos+1;			
			}
			else
			{
				firstXYPos.xPos = temp.xPos+1;
				firstXYPos.yPos = temp.yPos+1;					
			}
		return oldxylength;
	}		
	/**
	 * Find missing coin in the middle of a horizontal connected list.
	 * @return
	 */
	public VectorPos findMissingXCord()
	{
		sortY();
		int xval = Common.NOVALUE;
		int yval = Common.NOVALUE;
		int current = 0;
		int advance = 1;
		for(int i=0;i<list.size()-1;i++)
		{
			VectorPos p1 = list.get(current);
			VectorPos p2 = list.get(advance);
			if((p1.yPos == p2.yPos)&&(p2.xPos-p1.xPos==1))
			{	
				current++;
				advance++;			
			}
			else
			{
				if((current+2)<=list.size())
				{
					if((p1.yPos == p2.yPos) && (p2.xPos-p1.xPos)==2)
					{
						current = advance;
						xval = p2.xPos-1;
						yval = p2.yPos;
					}
					else
					{				
						advance++;
					}
				}
			}	
		}
		return new VectorPos(xval, yval);
	}
	/**
	 * Find missing coin in the middle of a diagonal connected list.
	 * @return
	 */
	public VectorPos findMissingXYCord()
	{
		VectorPos missingDiagonal = new VectorPos(Common.NOVALUE, Common.NOVALUE); 
		sortX();
		int currentUP = 0;
		int advanceUP = 1;
		int currentDOWN = 0;
		int advanceDOWN = 1;
		for(int i=0;i<list.size()-1;i++)
		{
			VectorPos testP1Up = list.get(currentUP);
			VectorPos testP2Up = list.get(advanceUP);
			VectorPos testP1Down = list.get(currentDOWN);
			VectorPos testP2Down = list.get(advanceDOWN);
			/*
			 * Test Ascending
			 */
			if( (testP1Up.xPos+1)==testP2Up.xPos && (testP1Up.yPos+1) == testP2Up.yPos)
			{	
				currentUP++;
				advanceUP++;			
			}
			else
			{
				if((currentUP+2)<=list.size())
				{
					if(((testP1Up.yPos+2) == testP2Up.yPos) && (testP2Up.xPos-testP1Up.xPos)==2)
					{
						currentUP = advanceUP;
						missingDiagonal.xPos = testP1Up.xPos+1;
						missingDiagonal.yPos = testP1Up.yPos+1;						
					}
					else { advanceUP++; }
				}
			}	
			/*
			 * Test descending
			 */
			if((testP1Down.xPos+1 == testP2Down.xPos) && (testP1Down.yPos-1) == testP2Down.yPos)
			{
				currentDOWN++;
				advanceDOWN++;			
			}
			else
			{
				if((currentDOWN+2)<=list.size())
				{
					if((testP1Down.xPos+2 == testP2Down.xPos) && (testP1Down.yPos-2) == testP2Down.yPos)
					{
						currentDOWN = advanceDOWN;
						missingDiagonal.xPos = testP1Down.xPos+1;
						missingDiagonal.yPos = testP1Down.yPos+1;	
					}
					else { advanceDOWN++; }
				}
			}			
		}
		// check if coordinate is legal
		if(checkCoordinate(missingDiagonal))
			return missingDiagonal;	
		else
			return new VectorPos(Common.NOVALUE, Common.NOVALUE);
		// return result
	}
	/**
	 * Check if the coordinate is within bonds
	 * @param koord
	 * @return
	 */
	public boolean checkCoordinate(VectorPos koord)
	{
		if(koord.xPos<Common.XSIZE && koord.xPos>=0)
			if(koord.yPos<Common.YSIZE && koord.yPos>=0)			
				return true;

		return false;
	}
	/**
	 * 
	 * @param vhp
	 * @param len
	 * @return
	 */
	public VectorPos getLongestXFreeCoordinate(VectorPosHandling vhp, int len)
	{
		ArrayList<VectorPos> end = new ArrayList<VectorPos>();
		int lengths[] = new int[40];
		sortX();
		int length = list.size();
		boolean FirstCheck = true;

		int xlength = 1;
		int lastx = 0;
		for(int i=1;i<length;i++)
		{
			VectorPos p1 = list.get(i-1);
			VectorPos p2 = list.get(i);
			if((p1.yPos == p2.yPos)&&(p2.xPos-p1.xPos)==1)
			{
				if(FirstCheck)
				{
					end.add(p1);
					FirstCheck = false;
				}
				xlength++;	
				lengths[lastx] = xlength;
			}
			else
			{
				lastx++;
				FirstCheck = true;
				xlength = 1;
			}
		}
		/*
		 * Find free koordinate for the largest connected
		 */
		for(int i=0;i<end.size();i++)
		{
			if(lengths[i]==len)
			{
				if((end.get(i).xPos-1)>=0 && (end.get(i).xPos+len)<Common.XSIZE )
				{	
					if(!vhp.checkPosition(new VectorPos(end.get(i).xPos-1,end.get(i).yPos))) 
						return new VectorPos(end.get(i).xPos-1, end.get(i).yPos);

					if( !vhp.checkPosition(new VectorPos(end.get(i).xPos+3,end.get(i).yPos)))
						return new VectorPos(end.get(i).xPos+len, end.get(i).yPos);
				}
			}
		}
		// return failed
		return new VectorPos(Common.NOVALUE, Common.NOVALUE);
	}
	/**
	 * Find the free coordinate for the largest vertical connected list
	 * @param vhp
	 * @param len
	 * @return
	 */
	public VectorPos getLongestYFreeCoordinate(VectorPosHandling vhp, int len)
	{
		ArrayList<VectorPos> end = new ArrayList<VectorPos>();
		sortX();
		int ylength = 1;
		for(int i=1;i<list.size();i++)
		{
			VectorPos p1 = list.get(i-1);
			VectorPos p2 = list.get(i);
			if((p1.xPos == p2.xPos)&&(p2.yPos-p1.yPos)==1) { ylength++; }
			else
			{
				if(ylength==len) { end.add(p1); }
				ylength = 1;
			}
		}
		/*
		 * Find free koordinate for the largest connected Vertical
		 */
		for(int i=0;i<end.size();i++)
		{
			if((end.get(i).yPos+1)<Common.YSIZE)
			{					
				if(!vhp.checkPosition(new VectorPos(end.get(i).xPos,end.get(i).yPos+1))) 
					return new VectorPos(end.get(i).xPos, end.get(i).yPos+1);
			}
		}
		// return failed
		return new VectorPos(Common.NOVALUE, Common.NOVALUE);
	}
	/**
	 * VectorPos getLastYPosition()
	 * Returns a pointer to a vector position from the last Y connect
	 * @return
	 */
	public VectorPos getLastYPosition() { return firstYPos; }
	/**
	 * VectorPos getLastX-yPosition()
	 * Returns a pointer to a vector position from the last XY connect
	 * @return
	 */
	public VectorPos getMissingXYPosition() { return firstXYPos; }
	/**
	 * VectorPos getLastXPosition()
	 * Returns a pointer to a vector position from the last X connect
	 * @return
	 */
	public VectorPos getLastXPosition() { return firstXPos; }	
	/**
	 * int getWinnerState()
	 * 
	 * Determine who are closest to a win, by counting the Horizonalt, vertical and
	 * Diagonal positions.
	 * @return 
	 * 
	 * the largest number of these 3
	 */
	public int getWinnerState(int playerID)
	{
		int largeX = this.getLongestX();
		int largeY = this.getLongestY();
		int largeXY = this.getLongestXY();
		
		Common.debug("CURRENT STATE for "+playerID+" : largeX "+largeX+" largeY "+largeY+" largeXY "+largeXY );

		int maxValue = Math.max(largeX , largeY);
		maxValue = Math.max(maxValue , largeXY);
		return maxValue;				
	}
	/**
	 * End of class
	 */
}